pub struct Luhn {
    content: String,
}

impl Luhn {
    pub fn is_valid(&self) -> bool {
        let tmp = self.content.chars().filter(|&c| c != ' ').map(|v| v).collect::<Vec<char>>();
        if tmp.is_empty() || tmp.len() < 2 { return false; }
        let li = tmp.iter().rev().enumerate();
        let mut sum = 0_u32;
        for (index, &c) in li {
            if c < '0' || c > '9' {
                return false;
            } else {
                let result: u32 = c.to_digit(10).unwrap();
                let idx = index + 1;
                if idx % 2 == 0 {
                    let i = result * 2;
                    if i >= 10 {
                        let i1 = i % 10;
                        let i2 = i / 10;
                        sum = sum + i1 + i2;
                    } else {
                        sum = sum + i;
                    }
                } else {
                    sum = sum + result;
                }
            }
        }
        return !tmp.is_empty() && sum % 10 == 0;
    }
}

/// Here is the example of how the From trait could be implemented
/// for the &str type. Naturally, you can implement this trait
/// by hand for the every other type presented in the test suite,
/// but your solution will fail if a new type is presented.
/// Perhaps there exists a better solution for this problem?
impl<T> From<T> for Luhn
    where
        T: ToString,
{
    fn from(input: T) -> Self {
        let string = input.to_string();
        Luhn {
            content: string
        }
    }
}


#[test]
fn you_can_validate_from_a_str() {
    let valid = Luhn::from("046 454 286");
    let invalid = Luhn::from("046 454 287");
    assert!(valid.is_valid());
    assert!(!invalid.is_valid());
}

#[test]
#[ignore]
fn you_can_validate_from_a_string() {
    let valid = Luhn::from(String::from("046 454 286"));
    let invalid = Luhn::from(String::from("046 454 287"));
    assert!(valid.is_valid());
    assert!(!invalid.is_valid());
}

#[test]
#[ignore]
fn you_can_validate_from_a_u8() {
    let valid = Luhn::from(240u8);
    let invalid = Luhn::from(241u8);
    assert!(valid.is_valid());
    assert!(!invalid.is_valid());
}

#[test]
#[ignore]
fn you_can_validate_from_a_u16() {
    let valid = Luhn::from(64_436u16);
    let invalid = Luhn::from(64_437u16);
    assert!(valid.is_valid());
    assert!(!invalid.is_valid());
}

#[test]
#[ignore]
fn you_can_validate_from_a_u32() {
    let valid = Luhn::from(46_454_286u32);
    let invalid = Luhn::from(46_454_287u32);
    assert!(valid.is_valid());
    assert!(!invalid.is_valid());
}

#[test]
#[ignore]
fn you_can_validate_from_a_u64() {
    let valid = Luhn::from(8273_1232_7352_0562u64);
    let invalid = Luhn::from(8273_1232_7352_0569u64);
    assert!(valid.is_valid());
    assert!(!invalid.is_valid());
}

#[test]
#[ignore]
fn you_can_validate_from_a_usize() {
    let valid = Luhn::from(8273_1232_7352_0562usize);
    let invalid = Luhn::from(8273_1232_7352_0569usize);
    assert!(valid.is_valid());
    assert!(!invalid.is_valid());
}

#[test]
#[ignore]
fn single_digit_string_is_invalid() {
    assert!(!Luhn::from("1").is_valid());
}

#[test]
#[ignore]
fn single_zero_string_is_invalid() {
    assert!(!Luhn::from("0").is_valid());
}

#[test]
#[ignore]
fn valid_canadian_sin_is_valid() {
    assert!(Luhn::from("046 454 286").is_valid());
}

#[test]
#[ignore]
fn invalid_canadian_sin_is_invalid() {
    assert!(!Luhn::from("046 454 287").is_valid());
}

#[test]
#[ignore]
fn invalid_credit_card_is_invalid() {
    assert!(!Luhn::from("8273 1232 7352 0569").is_valid());
}

#[test]
#[ignore]
fn strings_that_contain_non_digits_are_invalid() {
    assert!(!Luhn::from("046a 454 286").is_valid());
}

#[test]
#[ignore]
fn input_digit_9_is_still_correctly_converted_to_output_digit_9() {
    assert!(Luhn::from("091").is_valid());
}


